# pylint: disable-msg=E1101
"""
@author: Sergiy Tsymbalyuk
"""

import logging
from datetime import datetime, date, timedelta

from pylons import tmpl_context as c, request, url
from pylons.i18n import lazy_ugettext as _
from pylons.controllers.util import redirect
from sqlalchemy import desc, func, select, or_
from repoze.what.plugins.pylonshq import ActionProtector
from repoze.what.predicates import has_permission, not_anonymous

from formalchemy import Field, types

from chowa.lib.site.navigation import Tab, get_page
from chowa.lib.site.forms import TabularFieldSet
from chowa.model.abstract import Person
from chowa.model.auth import User
from chowa.model.organization import Institution, Division
from hrms.model.person import Employee

from catalogue.lib.base import BaseController, render, Session
from catalogue.model.catalog import *

log = logging.getLogger(__name__)

def _years_filter(query):
    # apply before paginate
    years_query = query.group_by(func.year(Document.approved))
    years_query = years_query.filter(func.year(Document.approved) >= 2010).order_by('approved')
    c.years = ['...', '199..', '200..'] + [str(doc.approved.year) for doc in years_query]
    c.year = request.params.get('year') or '...'
    if not c.year == '...':
        if '..' in c.year:
            start = c.year.replace('..', '0')
            end = c.year.replace('..', '9')
            query = query.filter(func.year(Document.approved) >= start)
            query = query.filter(func.year(Document.approved) <= end)
        else:
            query = query.filter(func.year(Document.approved) == c.year)
    return query


def _get_documents(query):
    query = _years_filter(query)
    c.documents = get_page(query, items_per_page=8)

def _get_my_division():
    try:
        user = request.environ.get('repoze.who.identity')['user']
        query = Session.query(Employee).join(User).filter(User.id == user.id)
        employee = query.one()
        return employee.division
    except:
        return None


class DocsController(BaseController):
    def __init__(self):
        # primary tab for all documents
        tabs = [Tab(params=dict(action='index'),
                    ignore_params=['id', 'institution'],
                    caption=_('All'))]
        # secondary tab for unknown type documents
        other_tabs = [Tab(params=dict(action='other', id='0'),
                          ignore_params=['institution'],
                          caption=_('Unknown'))]
        
        count_all = Session.query(Document).count()
        query = select([Document.type_id, func.count(Document.id).label('doc_count')])
        query = query.group_by(Document.type_id)
        types = Session.execute(query)
        for type in types:
            tid = type['type_id']
            # ignore none type documents
            if not tid is None and tid > 0:
                # types with document count over 1% move to primary tabs
                if type['doc_count'] > count_all / 100:
                    tabs += [Tab(params=dict(action='type', id=str(tid), default__institution='all'),
                                 caption=Session.query(DocumentType).get(tid))]
                # types with document count from 1 to 1% move to secondary tabs in 'other' tab
                elif type['doc_count'] > 0:
                    other_tabs += [Tab(params=dict(action='other', id=str(tid)),
                                       ignore_params=['institution'],
                                       caption=Session.query(DocumentType).get(tid))]
        # 'other' tab, have default secondary tab 'unknown'
        tabs += [Tab(params=dict(action='other', default__id='0'),
                     ignore_params=['institution'],
                     caption=_('Other'))]
        
        # initialize tabs
        self.__primary_tabs__ = [tabs]
        self.__secondary_tabs__ = [other_tabs]
        # secondary tabs
        doc_query = select([Document.type_id, Document.institution_id])
        doc_query = doc_query.group_by(Document.type_id, Document.institution_id).alias('doc')
        types = Session.execute(query)
        for type in types:
            tid = type['type_id']
            query = select([doc_query.c.institution_id]).select_from(doc_query)
            query = query.where(doc_query.c.type_id == tid)
            result = Session.execute(query)
            # all types with more than one institution have secondary tabs
            if result.rowcount > 1:
                tabs = [Tab(params=dict(action='type', id=str(tid), institution='all'),
                            caption=_('All'))]
                for institution in result:
                    iid = institution['institution_id']
                    if iid:
                        inst = Session.query(Institution).get(iid)
                        tabs += [Tab(params=dict(action='type', id=str(tid),
                                                 institution=str(iid)),
                                     caption=inst.short_name,
                                     description=inst.full_name)]
                self.__secondary_tabs__ += [tabs]
                
    def __after__(self):
        Session.close()
    
    def index(self):
        query = Session.query(Document)
        _get_documents(query)
        return render('/catalogue/docs/index.html')
    
    def type(self, id, institution=None):
        query = Session.query(Document)
        query = query.filter_by(type_id=id)
        if not institution in [None, 'all']:
            query = query.filter_by(institution_id=institution)
        _get_documents(query)
        return render('/catalogue/docs/index.html')
    
    def other(self, id):
        return self.type(id)
    
    def users(self):
        query = select([User.id, Person.surname, Person.name, func.count(Document.id).label('docs_count')])
        query = query.where(Document.author_id == User.id)
        query = query.where(User.person_id == Person.id)
        query = query.group_by(User.id)
        query = query.order_by(desc('docs_count'))
        c.users = Session.execute(query)
        return render('/catalogue/users.html')
    
    def user(self, id):
        """View documents posted by given author."""
        c.user = Session.query(User).get(id)
        
        query = Session.query(Document).filter_by(author_id=id)
        _get_documents(query)
        return render('/catalogue/docs/user.html')
    
    @ActionProtector(not_anonymous())
    def my(self):
        user = request.environ.get('repoze.who.identity')['user']
        return self.user(user.id)
        
    @ActionProtector(not_anonymous())
    def favorites(self):
        """View favorite documents."""
        c.user = request.environ.get('repoze.who.identity')['user']
        
        query = Session.query(Document).join(user_favorites)
        query = query.filter(user_favorites.c.user_id == c.user.id)
        _get_documents(query)
        return render('/catalogue/docs/favorites.html')
    
    def divisions(self):
        query = Session.query(Division)
        query = query.join(Employee, User, Document)
        c.divisions = query.all()
        return render('/catalogue/divisions.html')
    
    def division(self, id):
        """View documents posted by given department's authors."""
        c.division = Session.query(Division).get(id)
        
        my_division = _get_my_division()
        
        query = Session.query(Document)
        query = query.join(User, Employee)
        query = query.filter(Employee.division_id == id)
        _get_documents(query)
        return render('/catalogue/docs/division.html')
    
    def my_division(self):
        # FIXME: no division exception 
        division = _get_my_division()
        id = division.id
        return redirect(url.current(action='division', id=id))
    
    def sections(self, id=None):
        """View sections list."""
        if id is None:
            c.sections = Session.query(TopSection).all()
            return render('/catalogue/top_sections.html')
        else:
            c.section = Session.query(Section).get(id)
            
            query = Session.query(SubSection)
            c.sections = query.filter_by(parent_id=id).all()
            
            query = Session.query(Document).join(document_sections)
            query = query.filter(document_sections.c.section_id == id)
            _get_documents(query)
            return render('/catalogue/docs/sections.html')
    
    def section(self, id):
        """View documents by sections."""
        c.section = Session.query(Section).get(id)
        
        query = Session.query(Document)
        query = query.join(document_sections)
        query = query.filter(document_sections.c.section_id == id)
        _get_documents(query)
        return render('/catalogue/docs/section.html')
    
    def tag(self, id):
        """View documents that have given tag."""
        c.tag = Session.query(Tag).get(id)
        
        query = Session.query(Document)
        query = query.join(document_tags)
        query = query.filter(document_tags.c.tag_id == id)
        _get_documents(query)
        return render('/catalogue/docs/tag.html')
    
    def tags(self):
        """View all tags."""
        c.tags = Session.query(Tag).all()
        return render('/catalogue/tags.html')
    
    def recent(self):
        """View recent documents."""
        query = Session.query(Document)
        now = datetime.now()
        _from = now - timedelta(30, 0, 0)
        query = query.filter(Document.created >= _from)
        _get_documents(query)
        return render('/catalogue/docs/recent.html')
    
    def search(self):
        query = Session.query(Document)
        query = query.outerjoin(DocumentType)
        query = query.outerjoin(Institution)
        
        c.text = ''
        c.approved_from = ''
        c.approved_to = ''
        if request.params.get('search'):
            c.text = request.params.get('text')
            c.approved_from = request.params.get('approved_from') or None
            c.approved_to = request.params.get('approved_to') or None
            if c.text:
                tokens = c.text.split(' ')
                for token in tokens:
                    number = token
                    if len(number) > 0 and number[0] == '#':
                        number = number[1:]
                    query = query.filter(
                        or_(
                            Document.title.like('%%%s%%' % token),
                            Document.number == number,
                            DocumentType.name.like('%%%s%%' % token),
                            Institution.short_name.like('%%%s%%' % token),
                            Institution.full_name.like('%%%s%%' % token),
                        ))
            if c.approved_from:
                approved_from = datetime.strptime(c.approved_from, '%d-%m-%Y')
                query = query.filter(Document.approved >= approved_from)
            if c.approved_to:
                approved_to = datetime.strptime(c.approved_to, '%d-%m-%Y')
                query = query.filter(Document.approved <= approved_to)
        else:
            query = query.filter(Document.id < 0)
        _get_documents(query)
        return render('/catalogue/docs/search.html')
        